import { parseTime } from "@/utils/skst";
import CryptoJS from 'crypto-js';

/**
 * 表格时间格式化
 */
export function formatDate(date, format) {
  format = format || "yyyy-MM-dd hh:mm:ss";
  date = new Date(date);
  const o = {
    "M+": date.getMonth() + 1,
    "d+": date.getDate(),
    "h+": date.getHours(),
    "m+": date.getMinutes(),
    "s+": date.getSeconds(),
    "q+": Math.floor((date.getMonth() + 3) / 3),
    S: date.getMilliseconds(),
  };
  if (/(y+)/.test(format)) {
    format = format.replace(
      RegExp.$1,
      (date.getFullYear() + "").substr(4 - RegExp.$1.length)
    );
  }
  for (var k in o) {
    if (new RegExp("(" + k + ")").test(format)) {
      format = format.replace(
        RegExp.$1,
        RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
      );
    }
  }
  return format;
}

export function addDate(date, num) {
  date = new Date(date);
  date.setDate(date.getDate() + num);
  return formatDate(date, "yyyy-MM-dd");
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time, option) {
  if (("" + time).length === 10) {
    time = parseInt(time) * 1000;
  } else {
    time = +time;
  }
  const d = new Date(time);
  const now = Date.now();

  const diff = (now - d) / 1000;

  if (diff < 30) {
    return "刚刚";
  } else if (diff < 3600) {
    // less 1 hour
    return Math.ceil(diff / 60) + "分钟前";
  } else if (diff < 3600 * 24) {
    return Math.ceil(diff / 3600) + "小时前";
  } else if (diff < 3600 * 24 * 2) {
    return "1天前";
  }
  if (option) {
    return parseTime(time, option);
  } else {
    return (
      d.getMonth() +
      1 +
      "月" +
      d.getDate() +
      "日" +
      d.getHours() +
      "时" +
      d.getMinutes() +
      "分"
    );
  }
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url) {
  url = url == null ? window.location.href : url;
  const search = url.substring(url.lastIndexOf("?") + 1);
  const obj = {};
  const reg = /([^?&=]+)=([^?&=]*)/g;
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1);
    let val = decodeURIComponent($2);
    val = String(val);
    obj[name] = val;
    return rs;
  });
  return obj;
}

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str) {
  // returns the byte length of an utf8 string
  let s = str.length;
  for (var i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) s++;
    else if (code > 0x7ff && code <= 0xffff) s += 2;
    if (code >= 0xdc00 && code <= 0xdfff) i--;
  }
  return s;
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual) {
  const newArray = [];
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i]);
    }
  }
  return newArray;
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json) {
  if (!json) return "";
  return cleanArray(
    Object.keys(json).map((key) => {
      if (json[key] === undefined) return "";
      return encodeURIComponent(key) + "=" + encodeURIComponent(json[key]);
    })
  ).join("&");
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url) {
  const search = decodeURIComponent(url.split("?")[1]).replace(/\+/g, " ");
  if (!search) {
    return {};
  }
  const obj = {};
  const searchArr = search.split("&");
  searchArr.forEach((v) => {
    const index = v.indexOf("=");
    if (index !== -1) {
      const name = v.substring(0, index);
      const val = v.substring(index + 1, v.length);
      obj[name] = val;
    }
  });
  return obj;
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement("div");
  div.innerHTML = val;
  return div.textContent || div.innerText;
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== "object") {
    target = {};
  }
  if (Array.isArray(source)) {
    return source.slice();
  }
  Object.keys(source).forEach((property) => {
    const sourceProperty = source[property];
    if (typeof sourceProperty === "object") {
      target[property] = objectMerge(target[property], sourceProperty);
    } else {
      target[property] = sourceProperty;
    }
  });
  return target;
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return;
  }
  let classString = element.className;
  const nameIndex = classString.indexOf(className);
  if (nameIndex === -1) {
    classString += "" + className;
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length);
  }
  element.className = classString;
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
  if (type === "start") {
    return new Date().getTime() - 3600 * 1000 * 24 * 90;
  } else {
    return new Date(new Date().toDateString());
  }
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result;

  const later = function () {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp;

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last);
    } else {
      timeout = null;
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args);
        if (!timeout) context = args = null;
      }
    }
  };

  return function (...args) {
    context = this;
    timestamp = +new Date();
    const callNow = immediate && !timeout;
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait);
    if (callNow) {
      result = func.apply(context, args);
      context = args = null;
    }

    return result;
  };
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source) {
  if (!source && typeof source !== "object") {
    throw new Error("error arguments", "deepClone");
  }
  const targetObj = source.constructor === Array ? [] : {};
  Object.keys(source).forEach((keys) => {
    if (source[keys] && typeof source[keys] === "object") {
      targetObj[keys] = deepClone(source[keys]);
    } else {
      targetObj[keys] = source[keys];
    }
  });
  return targetObj;
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr));
}

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = +new Date() + "";
  const randomNum = parseInt((1 + Math.random()) * 65536) + "";
  return (+(randomNum + timestamp)).toString(32);
}

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele, cls) {
  return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
}

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele, cls) {
  if (!hasClass(ele, cls)) ele.className += " " + cls;
}

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele, cls) {
  if (hasClass(ele, cls)) {
    const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
    ele.className = ele.className.replace(reg, " ");
  }
}

export function makeMap(str, expectsLowerCase) {
  const map = Object.create(null);
  const list = str.split(",");
  for (let i = 0; i < list.length; i++) {
    map[list[i]] = true;
  }
  return expectsLowerCase ? (val) => map[val.toLowerCase()] : (val) => map[val];
}

export const exportDefault = "export default ";

export const beautifierConf = {
  html: {
    indent_size: "2",
    indent_char: " ",
    max_preserve_newlines: "-1",
    preserve_newlines: false,
    keep_array_indentation: false,
    break_chained_methods: false,
    indent_scripts: "separate",
    brace_style: "end-expand",
    space_before_conditional: true,
    unescape_strings: false,
    jslint_happy: false,
    end_with_newline: true,
    wrap_line_length: "110",
    indent_inner_html: true,
    comma_first: false,
    e4x: true,
    indent_empty_lines: true,
  },
  js: {
    indent_size: "2",
    indent_char: " ",
    max_preserve_newlines: "-1",
    preserve_newlines: false,
    keep_array_indentation: false,
    break_chained_methods: false,
    indent_scripts: "normal",
    brace_style: "end-expand",
    space_before_conditional: true,
    unescape_strings: false,
    jslint_happy: true,
    end_with_newline: true,
    wrap_line_length: "110",
    indent_inner_html: true,
    comma_first: false,
    e4x: true,
    indent_empty_lines: true,
  },
};

// 首字母大小
export function titleCase(str) {
  return str.replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
}

// 下划转驼峰
export function camelCase(str) {
  return str.replace(/_[a-z]/g, (str1) => str1.substr(-1).toUpperCase());
}

export function isNumberStr(str) {
  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str);
}

export function getRowIdentity(row, rowKey) {
  if (
    row === undefined ||
    row.length <= 0 ||
    rowKey === undefined ||
    rowKey.length <= 0
  )
    return "";
  if (typeof rowKey === "string") {
    if (rowKey.indexOf(".") < 0) {
      return row[rowKey];
    }
    const key = rowKey.split(".");
    let current = row;
    for (let i = 0; i < key.length; i++) {
      current = current[key[i]] ? current[key[i]] : "";
    }
    return current;
  } else if (typeof rowKey === "function") {
    return rowKey(row);
  }
}

export function treeChildEmpty(data, props, replace) {
  let arr = [];
  if (typeof data !== "undefined") {
    const fn = (data) => {
      arr = data.map((current) => {
        current.disabled =
          replace.includes(current[props.label]) ||
          replace.includes(current[props.value]);
        const item = current[props.children];
        if (item && item.length > 0) {
          fn(item, props, replace);
        } else {
          delete current[props.children];
        }
        return current;
      });
    };
    fn(data, props, replace);
  }
  return arr;
}

/* 日期转成时间戳（秒级） */
export function dateChangetosecond(date) {
  let result;
  let dateFlage = new Date(date);
  if (dateFlage) {
    result = dateFlage.getTime() / 1000;
    return result;
  } else {
    return (result = "非标准日期格式");
  }
}

export function addZero(num) {
  if (parseInt(num) < 10) {
    num = "0" + num;
  }
  return num;
}
/* 时间戳(秒级)转成日期 */
export function secondChangedate(ms) {
  if (ms) {
    var oDate = new Date(ms),
      oYear = oDate.getFullYear(),
      oMonth = oDate.getMonth() + 1,
      oDay = oDate.getDate(),
      oHour = oDate.getHours(),
      oMin = oDate.getMinutes(),
      oSen = oDate.getSeconds(),
      oTime =
        oYear +
        "-" +
        addZero(oMonth) +
        "-" +
        addZero(oDay) +
        " " +
        addZero(oHour) +
        ":" +
        addZero(oMin) +
        ":" +
        addZero(oSen);
    return oTime;
  } else {
    return "";
  }
}

/* 数据处理：数据除以num且保留fixed位小数，输出为type类型的数据
 *@param
 *@num:除以倍数
 */
export function dealElectricity(el, num = 100, fixed = 2, type = "string") {
  if (!el) {
    el = 0;
  }
  let result, result2;
  if (typeof el == "number") {
    result = (el / num).toFixed(fixed);
  } else if (typeof el == "string") {
    let nm = Number(el);
    if (nm == NaN) {
      result = 0;
    } else {
      result = (nm / num).toFixed(fixed);
    }
  }
  if (type == "number") {
    result = Number(result);
    return result
  } else {
    result += '';
    let x = result.split('.');
    let x1 = x[0];
    let x2 = x.length > 1 ? '.' + x[1] : '';
    let reg = /(\d+)(\d{3})/;
    while (reg.test(x1)) {
      x1 = x1.replace(reg, '$1' + ',' + '$2');
      // x2 = x2.replace(reg, '$1' + ',' + '$2');
    }
    result2 = x1 + x2;
    return result2
  }

}

/* 数据处理：数据除以num且保留fixed位小数，输出为type类型的数据
 *@param
 *@num:除以倍数
 */
export function dealElectricity2(el, num = 100, fixed = 2, type = 'string') {
  let result;
  if (typeof el == "number") {
    result = (el / num).toFixed(fixed)
  } else if (typeof el == "string") {
    let nm = Number(el);
    if (nm == NaN) {
      result = 0
    } else {
      result = (nm / num).toFixed(fixed)
    }
  }
  if (type == 'number') {
    result = Number(result)
  }
  return result
}

/* 小数精确到digit位
 *@param
 *@val:{type:Number}
 *@decimal:所保留的小数位个数
 */
export function replaceDigit(value, digit, defeat = true) {
  value = String(value);
  if (!value) return "";
  value = value.replace(/[^\d.]/g, ""); // 清除“数字”和“.”以外的字符
  value = value.replace(/\.{2,}/g, "."); // 只保留第一个. 清除多余的
  value = value.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
  let reg = /^(\-)*(\d+)\.(\d\d).*$/;
  if (defeat === true) {
    if (digit && digit > 0) {
      const d = `\\d`;
      let re = ``;
      for (let i = 0; i < digit; i++) {
        re += d;
      }
      let txt = `^(\\d+)\\.(${re}).*$`;
      reg = new RegExp(txt);
    }
    value = value.replace(reg, "$1.$2"); // 只能输入digit个小数
  }
  if (value.indexOf(".") < 0 && value !== "") {
    // 以上已经过滤，此处控制的是如果没有小数点，首位不能为类似于 01、02的校验
    value = parseFloat(value);
  }
  return value;
}

/**
 * 数字只能是整数
 * @param {Number} v 原始数字
 * @return {Number} 数字
 */
export function replaceInteger(value) {
  if (!value) return null;
  value = String(value);
  value = value.replace(/[^\d]/g, ""); // 清除“数字”外的字符
  value = value.replace(/\.{2,}/g, "."); // 只保留第一个. 清除多余的
  value = value.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
  let reg = /\D/g;
  value = value.replace(reg, "");
  return Number(value);
}

/**
 * 只能输入1-9 的单一数字
 * @param {Number} v 原始数字
 * @return {Number} 数字
 */
export function onlyOnenumber(value) {
  if (!value) return "";
  value = String(value);
  if (value.length == 1) {
    value = value.replace(/[^0-9]/g, "");
    return value;
  }
}

/**
 * 只能输入数字和英文
 * @param {Number} v 原始输入
 * @return {Number} 数字
 */
export function allowNumberandletter(value) {
  if (!value) return "";
  value = String(value);
  if (value.length == 1) {
    value = value.replace(/[\W]/g, "");
    return value;
  }
}

export const isJSON = (str) => {
  if (typeof str == "string") {
    try {
      JSON.parse(str);
      return true;
    } catch (e) {
      return false;
    }
  }
};

/*
          函数：乘法函数，用来得到精确的乘法结果
          说明：函数返回较为精确的乘法结果。
          参数：arg1：第一个乘数；arg2第二个乘数；d要保留的小数位数（可以不传此参数，如果不传则不处理小数位数)
          调用：Calc.Mul(arg1,arg2)
          返回值：两数相乘的结果
          */
export function mul(arg1, arg2) {
  var r1 = arg1.toString(),
    r2 = arg2.toString(),
    m,
    resultVal,
    d = arguments[2];
  m =
    (r1.split(".")[1] ? r1.split(".")[1].length : 0) +
    (r2.split(".")[1] ? r2.split(".")[1].length : 0);
  resultVal =
    (Number(r1.replace(".", "")) * Number(r2.replace(".", ""))) /
    Math.pow(10, m);
  return typeof d !== "number"
    ? Number(resultVal)
    : Number(resultVal.toFixed(parseInt(d)));
}

/*
        函数：除法函数，用来得到精确的除法结果
        说明：函数返回较为精确的除法结果。
        参数：arg1：除数；arg2被除数；d要保留的小数位数（可以不传此参数，如果不传则不处理小数位数)
        调用：Calc.Div(arg1,arg2)
        返回值：arg1除于arg2的结果
        */
export function division(arg1, arg2) {
  var r1 = arg1.toString(),
    r2 = arg2.toString(),
    m,
    resultVal,
    d = arguments[2];
  m =
    (r2.split(".")[1] ? r2.split(".")[1].length : 0) -
    (r1.split(".")[1] ? r1.split(".")[1].length : 0);
  resultVal =
    (Number(r1.replace(".", "")) / Number(r2.replace(".", ""))) *
    Math.pow(10, m);
  return typeof d !== "number"
    ? Number(resultVal)
    : Number(resultVal.toFixed(parseInt(d)));
}

//校验地址
export function isUrl(str) {
  const reg = new RegExp(
    /^(([01]?[\d]{1,2})|(2[0-4][\d])|(25[0-5]))(\.(([01]?[\d]{1,2})|(2[0-4][\d])|(25[0-5]))){3}$/
  );
  return reg.test(str);
}

/**
 * 获取前几个月-选取前一个月或者包含当月
 * @param {Number} few 前几个月
 * @param {Boolen} flag true 包含当月 false 不包含当月
 * @return {Array} 年-月份集合
 */
export function recentlyYearMonth(few, flag = false) {
  let datelist = [];
  let date = new Date();
  let Y = date.getFullYear();
  let M;
  if (flag) {
    M = date.getMonth() + 1;
  } else {
    M = date.getMonth();
  }
  for (let i = 0; i < few; i++) {
    let dateoption = "";
    if (M - 1 >= 0) {
      Y = Y;
      M = M;
    } else {
      M = 12;
      Y = Y - 1;
    }
    let m = M;
    m = m < 10 ? "0" + m : m;
    dateoption = Y + "-" + m;
    M--;
    datelist.push(dateoption);
  }
  return datelist;
}

//加法
export function accAdd(arg1, arg2) {
  let r1, r2;
  try {
    r1 = arg1.toString().split('.')[1].length;
  } catch (e) {
    r1 = 0;
  }
  try {
    r2 = arg2.toString().split('.')[1].length;
  } catch (e) {
    r2 = 0;
  }
  const m = Math.pow(10, Math.max(r1, r2));
  return (arg1 * m + arg2 * m).toFixed(2) / m;
}

//减法
export function subtr(arg1, arg2) {
  var r1, r2, m, n;
  try {
    r1 = arg1.toString().split(".")[1].length
  } catch (e) {
    r1 = 0
  }
  try {
    r2 = arg2.toString().split(".")[1].length
  } catch (e) {
    r2 = 0
  }
  m = Math.pow(10, Math.max(r1, r2));
  n = (r1 >= r2) ? r1 : r2;
  return ((arg1 * m - arg2 * m) / m).toFixed(n);
}

/**
 * AES加密方法
 * @param {*} data 明文
 * @param {*} AES_KEY 密钥
 * @returns 密文
 */
// aes加密
export function encryptData(data, AES_KEY) {
  // return CryptoJS.AES.encrypt(data, key).toString();
  const key = CryptoJS.enc.Utf8.parse(AES_KEY);
  let iv = CryptoJS.enc.Utf8.parse(AES_KEY);
  // console.log(iv, 'iv')
  var encrypted = CryptoJS.AES.encrypt(data, key, {
    iv, mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.Pkcs7,
  });
  return encrypted.toString(); // 返回加密结果字符串
}


// 将查询参数存入对象并字符化
export function saveQuery(name, obj) {
  let result;
  if (Object.keys(obj).length > 0) {
    result = JSON.stringify(obj);
    localStorage.setItem(name, result);
  }
  return result;
}

// 将字符化的查询参数对象化并取出
/**
 * AES加密方法
 * @param {*} name 获取的对象名称
 * @param {*} from 来自哪个页面的路由
 * @param {*} rightArr 符合条件的路由集合
 * @returns Object
 */
export function outQuery(name, from, rightArr) {
  let result;
  let str = localStorage.getItem(name);
  if (str && str.length > 0) {
    if (rightArr.length > 0 && rightArr.includes(from)) {
      result = JSON.parse(str);
    } else {
      // 如果来的路由不是该页面的详情页面
      result = {}
    }
    localStorage.removeItem(name);
  } else {
    // 若是没有找到存储对象（第一次或者已经删除则返回空对象与页面数据合并）
    result = {}
  }
  return result;
}

// 计算等级评价分数
/**
 * @param {*} num1 单位建筑面积能耗数值
 * @param {*} num2 人均综合能耗
 * @returns Object num： 具体分数（0-20; color: 对应颜色（绿：>16 分，蓝：>10 且≦16，黄：>2 且≦10，红：≦2）
 */
export function levelCalculate(num1, num2) {
  let result = {
    num: 0,
    color: "",
  }
  //! 人均综合能耗为0的时候不计算等级评价分数
  /* 对于单位建筑面积能耗数值
    num1>9.5  0分
    9.5>=num1>6.0 2-5分
    6.0>=num1>4 6-8分
    4>=num1>0.4 9分
    0.4>=num1>0 10分
  */
  /* 对于人均综合能耗
    num2>450  0分
    450>=num2>230 2-5分
    230>=num2>140 6-8分
    140>=num2>14 9分
    14>=num2>0 10分
  */
  let resultNum1 = 0;// 单位建筑面积能耗的分数
  let resultNum2 = 0;// 人均综合能耗的分数
  if (num2 == 0) {
    result = {
      num: 0,
      color: "gray",
    }
  } else {
    if (num1 > 9.5) {
      resultNum1 = 0;
    }
    if (num1 > 6.0 && num1 <= 9.5) {
      resultNum1 = duringMate(num1, [9.5, 6.0], [2, 5]);
    }
    if (num1 > 4.0 && num1 <= 6.0) {
      resultNum1 = duringMate(num1, [6.0, 4.0], [6, 8]);
    }
    if (num1 > 3.6 && num1 <= 4.0) {
      resultNum1 = 9;
    }
    if (num1 >= 0 && num1 <= 3.6) {
      resultNum1 = 10;
    }
    if (num2 > 450) {
      resultNum2 = 0;
    }
    if (num2 > 230 && num2 <= 450) {
      resultNum2 = duringMate(num2, [450, 230], [2, 5]);
    }
    if (num2 > 140 && num2 <= 230) {
      resultNum2 = duringMate(num2, [230, 140], [6, 8]);
    }
    if (num2 > 126 && num2 <= 140) {
      resultNum2 = 9;
    }
    if (num2 > 0 && num2 <= 126) {
      resultNum2 = 10;
    }
    result.num = (resultNum1 * 10 + resultNum2 * 10) / 10;
    if (result.num > 16) {
      result.color = 'green'
    } else if (result.num > 10 && result.num <= 16) {
      result.color = 'blue'
    } else if (result.num > 2 && result.num <= 10) {
      result.color = 'yellow'
    } else if (result.num <= 2) {
      result.color = 'red'
    }
  }
  return result
}

// 计算区间占比对应的分数
/**
 * @param {*} target 计算的数值对象
 * @param {*} duringArr 数值区间数值 第一位 上限  第二位  下限
 * @param {*} mateArr 分数区间数值 第一位 下限  第二位  上限
 * @returns Object num： 具体分数
 */
export function duringMate(target, duringArr, mateArr) {
  let result;
  let x = duringArr[1];
  let y = duringArr[0];
  let a = mateArr[1];
  let b = mateArr[0];
  result = a + (target - x) * (b - a) / (y - x);
  result = dealElectricity2(result, 1, 1, 'number');
  return result
}
